package syM

import (
	"fmt"
	"db2s/Meta"
	"db2s/go-log/log"
	"db2s/outPut"
	"db2s/parDef"
	"db2s/ref"
	mq "db2s/topic-mq"
	"sync/atomic"
)

func objectJoinMatch(plan *SchedulePlan2) (AlterStatus bool, err error) {
	//判断目标端表是否存在，存在走alter，不存在走create
	var event = "[objectJoinMatch]"
	log.MainLog().Info(fmt.Sprintf("(%v) %v Start to determine the join method of Table %v", plan.Object.ObjectLogSeq, event, getTableName(plan.Object.Schema, plan.Object.Table)))
	if AlterStatus, err = GetTableExist(plan); err != nil {
		errorAction(plan, err, fmt.Sprintf("(%v) %v The join method for obtaining Table %v failed. error Msg:%v", plan.Object.ObjectLogSeq, event, getTableName(plan.Object.Schema, plan.Object.Table), err))
	}
	log.MainLog().Info(fmt.Sprintf("(%v) %v The join method in Table %v is %v", plan.Object.ObjectLogSeq, event, getTableName(plan.Object.Schema, plan.Object.Table), func() string {
		if AlterStatus {
			return "join"
		}
		return "left"
	}()))
	return
}

func repairMethodSplit(sqlGarth []fixSqlResult) (applySqlGarth []string) {
	switch GlobalPConfigs.repair.DataFix {
	case "table":
		for _, v := range sqlGarth {
			var createS string
			if v.createSql != nil {
				createS = fmt.Sprintf("%v", v.createSql)
			}
			applySqlGarth = append(applySqlGarth, fmt.Sprintf("%v", createS))
		}
	case "file":
		for _, v := range sqlGarth {
			var printS, createS string
			if v.printSql != nil {
				printS = fmt.Sprintf("%v", v.printSql)
			}
			if v.createSql != nil {
				createS = fmt.Sprintf("%v", v.createSql)
			}
			applySqlGarth = append(applySqlGarth, fmt.Sprintf("/* ######soruce object info ###### \n"+
				" %v \n "+
				"============   */\n\n"+
				"%v\n", printS, createS))
		}
	}
	return
}

func getFixFilePoint1(behavior bool, plan *SchedulePlan2) outPut.FileOperations {
	switch GlobalPConfigs.repair.FixFileWay {
	case "split":
		if behavior {
			return plan.fixFile.AlterFilePoint
		} else {
			return plan.fixFile.CreateFilePoint
		}
	case "many":
		return plan.fixFile.SchemaFilePoint
	}
	return nil
}
func runErrorAction(message mq.Message, err error) {
	return
}
func handleError(message mq.Message, event string, err error) {
	errMsg := ref.ErrAddPrintf(event, err)
	var plan = message.Properties["plan"].(*SchedulePlan2)
	if err == nil {
		return
	}
	PlanContext.TPodTableStatusSwap(plan.TPod.Status, "error")
	atomic.SwapInt64(plan.MQ.ErrStatus, -1)
	atomic.AddInt64(plan.Status.ErrEnd, -1)
	PlanContext.TaskBarSubsErrorSwap(plan.subTaskInfo, fmt.Sprintf("%v", err))
	if PlanContext.TaskBarSubsStatusGet(plan.subTaskInfo) != -2 {
		PlanContext.TaskBarSubsStatusSwap(plan.subTaskInfo, "error")
	}
	log.ErrorLog().ErrorS(fmt.Sprintf("%v", errMsg))
}
func applySql(behavior bool, plan *SchedulePlan2, sql1 string) (err error) {
	var event = "[execSql]"
	var timeOut int64
	c := Meta.NewMeta([]string{GlobalPConfigs.dSns.SrcDBName, GlobalPConfigs.dSns.DestDBName}, "right", plan.Object.Role)
	c.Parameter1 = append(c.Parameter1, parDef.Parameter{Con: GlobalPConfigs.db.Source.GetDB("single"),
		Object:  parDef.Object{Schema: plan.Object.Schema, Table: plan.Object.Table},
		Options: parDef.Options{RepairMethod: GlobalPConfigs.repair.DataFix},
		ExecDDL: parDef.ExecDDL{Sql: sql1, FilePoint: getFixFilePoint1(behavior, plan)},
	})
	c.Parameter1 = append(c.Parameter1, parDef.Parameter{Con: GlobalPConfigs.db.Target.GetDB("single"),
		Object:  parDef.Object{Schema: plan.Object.MSchema, Table: plan.Object.MTable},
		Options: parDef.Options{RepairMethod: GlobalPConfigs.repair.DataFix},
		ExecDDL: parDef.ExecDDL{Sql: sql1, FilePoint: getFixFilePoint1(behavior, plan)},
	})
	if err = c.ExecDDLObject(); err != nil {
		log.ErrorLog().Error(fmt.Sprintf("(%v) %v Table %v.%v failed to execute the ddl statement, with the error message is \"%v\", and the sql statement was executed as \"%v\"", plan.Object.ObjectLogSeq, event, plan.Object.Schema, plan.Object.Table, err, sql1))
		return err
	}
	log.MainLog().Info(fmt.Sprintf("(%v) %v Table %v.%v successful to execute the ddl statement, execution time is %vms", plan.Object.ObjectLogSeq, event, plan.Object.Schema, plan.Object.Table, timeOut))
	log.MainLog().Debug(fmt.Sprintf("(%v) %v Table %v.%v successful to execute the ddl statement, and the sql statement was executed as \"%v\" execution time is %vms", plan.Object.ObjectLogSeq, event, plan.Object.Schema, plan.Object.Table, sql1, timeOut))
	return
}
func execFixSql(message mq.Message) (err error) {
	var event = "[execFixSql]"
	var sqlGarthNew []fixSqlResult
	var behavior bool
	defer func() {
		if r := ref.RecoverPanic(event, recover()); err == nil && err != nil {
			err = r
		}
	}()
	var plan = message.Properties["plan"].(*SchedulePlan2)
	var sqlGarth = message.Properties["fixSqlResult"]
	var tableMeta1 = message.Properties["fixMeta"]
	switch sqlGarth.(type) {
	case []fixSqlResult:
		sqlGarthNew = sqlGarth.([]fixSqlResult)
	}
	switch tableMeta1.(type) {
	case *getTableMeta:
		behavior = tableMeta1.(*getTableMeta).AlterStatus
	case *GetObjectMeta:
		behavior = tableMeta1.(*GetObjectMeta).AlterStatus
	}
	log.MainLog().Info(fmt.Sprintf("(%v) %v Start executing the repair statement for Table %v...", plan.Object.ObjectLogSeq, event, getTableName(plan.Object.Schema, plan.Object.Table)))
	for _, v := range repairMethodSplit(sqlGarthNew) {
		if v == "" {
			handleError(message, event, err)
		}
		if err = applySql(behavior, plan, v); err != nil {
			handleError(message, event, err)
			return
		}
	}
	log.MainLog().Info(fmt.Sprintf("(%v) %v The repair statement in Table %v was executed successfully!!!", plan.Object.ObjectLogSeq, event, getTableName(plan.Object.Schema, plan.Object.Table)))
	return
}
